@objectstack/runtime 7.2.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -726,6 +726,52 @@ var init_seed_loader = __esm({
726
726
  }
727
727
  });
728
728
 
729
+ // src/package-state-store.ts
730
+ function sanitizeEnvironmentId(environmentId) {
731
+ const raw = (environmentId ?? process.env.OS_ENVIRONMENT_ID ?? DEFAULT_ENVIRONMENT_ID).trim();
732
+ const safe = raw.replace(/[^a-zA-Z0-9._-]/g, "_");
733
+ return safe.length > 0 ? safe : DEFAULT_ENVIRONMENT_ID;
734
+ }
735
+ function stateFilePath(environmentId) {
736
+ return (0, import_node_path2.join)(resolveObjectStackHome(), "package-state", `${sanitizeEnvironmentId(environmentId)}.json`);
737
+ }
738
+ function readState(environmentId) {
739
+ const file = stateFilePath(environmentId);
740
+ if (!(0, import_node_fs.existsSync)(file)) return {};
741
+ try {
742
+ const parsed = JSON.parse((0, import_node_fs.readFileSync)(file, "utf8"));
743
+ return parsed && typeof parsed === "object" ? parsed : {};
744
+ } catch {
745
+ return {};
746
+ }
747
+ }
748
+ function writeState(environmentId, state) {
749
+ const file = stateFilePath(environmentId);
750
+ (0, import_node_fs.mkdirSync)((0, import_node_path2.dirname)(file), { recursive: true });
751
+ (0, import_node_fs.writeFileSync)(file, `${JSON.stringify(state, null, 2)}
752
+ `, "utf8");
753
+ }
754
+ function loadDisabledPackageIds(environmentId) {
755
+ const disabled = readState(environmentId).disabled;
756
+ return new Set(Array.isArray(disabled) ? disabled.filter((id) => typeof id === "string") : []);
757
+ }
758
+ function setPackageDisabled(environmentId, packageId, disabled) {
759
+ const ids = loadDisabledPackageIds(environmentId);
760
+ if (disabled) ids.add(packageId);
761
+ else ids.delete(packageId);
762
+ writeState(environmentId, { disabled: Array.from(ids).sort() });
763
+ }
764
+ var import_node_fs, import_node_path2, DEFAULT_ENVIRONMENT_ID;
765
+ var init_package_state_store = __esm({
766
+ "src/package-state-store.ts"() {
767
+ "use strict";
768
+ import_node_fs = require("fs");
769
+ import_node_path2 = require("path");
770
+ init_standalone_stack();
771
+ DEFAULT_ENVIRONMENT_ID = "default";
772
+ }
773
+ });
774
+
729
775
  // src/sandbox/quickjs-runner.ts
730
776
  function installApiMethod(vm, parent, method, objectName, ctx, caps, required, origin) {
731
777
  const fn = vm.newAsyncifiedFunction(method, async (...argHandles) => {
@@ -1284,11 +1330,13 @@ function collectBundleFunctions(bundle) {
1284
1330
  merge(bundle?.manifest?.functions);
1285
1331
  return out;
1286
1332
  }
1287
- var AppPlugin;
1333
+ var import_types, AppPlugin;
1288
1334
  var init_app_plugin = __esm({
1289
1335
  "src/app-plugin.ts"() {
1290
1336
  "use strict";
1337
+ import_types = require("@objectstack/types");
1291
1338
  init_seed_loader();
1339
+ init_package_state_store();
1292
1340
  init_quickjs_runner();
1293
1341
  init_body_runner();
1294
1342
  AppPlugin = class {
@@ -1314,6 +1362,24 @@ var init_app_plugin = __esm({
1314
1362
  console.warn(
1315
1363
  `[AppPlugin:init] appId=${appId} keys=${Object.keys(servicePayload).join(",")} flows=${Array.isArray(servicePayload.flows) ? servicePayload.flows.length : "n/a"}`
1316
1364
  );
1365
+ try {
1366
+ const ql = ctx.getService("objectql");
1367
+ const setter = ql?.registry?.setInitialDisabledPackageIds;
1368
+ if (typeof setter === "function") {
1369
+ const disabled = loadDisabledPackageIds(this.projectContext?.environmentId);
1370
+ if (disabled.size > 0) {
1371
+ setter.call(ql.registry, disabled);
1372
+ ctx.logger.info("[AppPlugin] seeded persisted disabled packages", {
1373
+ environmentId: this.projectContext?.environmentId,
1374
+ disabled: Array.from(disabled)
1375
+ });
1376
+ }
1377
+ }
1378
+ } catch (err) {
1379
+ ctx.logger.warn("[AppPlugin] failed to seed persisted package state", {
1380
+ error: err?.message ?? String(err)
1381
+ });
1382
+ }
1317
1383
  ctx.getService("manifest").register(servicePayload);
1318
1384
  };
1319
1385
  this.start = async (ctx) => {
@@ -1614,7 +1680,7 @@ var init_app_plugin = __esm({
1614
1680
  } catch (e) {
1615
1681
  ctx.logger.warn("[Seeder] Failed to register seed-datasets/seed-replayer service", { error: e?.message });
1616
1682
  }
1617
- const multiTenant = String(process.env.OS_MULTI_TENANT ?? "false").toLowerCase() !== "false";
1683
+ const multiTenant = String((0, import_types.readEnvWithDeprecation)("OS_MULTI_ORG_ENABLED", "OS_MULTI_TENANT") ?? "false").toLowerCase() !== "false";
1618
1684
  if (multiTenant) {
1619
1685
  ctx.logger.info("[Seeder] multi-tenant mode \u2014 skipping inline seed; per-org replay will run on sys_organization insert");
1620
1686
  } else {
@@ -1858,6 +1924,170 @@ var init_app_plugin = __esm({
1858
1924
  }
1859
1925
  });
1860
1926
 
1927
+ // src/standalone-stack.ts
1928
+ function resolveObjectStackHome() {
1929
+ const raw = process.env.OS_HOME?.trim();
1930
+ if (raw && raw.length > 0) {
1931
+ if (raw.startsWith("~")) return (0, import_node_path3.resolve)((0, import_node_os.homedir)(), raw.slice(1).replace(/^[/\\]/, ""));
1932
+ return (0, import_node_path3.resolve)(raw);
1933
+ }
1934
+ return (0, import_node_path3.resolve)((0, import_node_os.homedir)(), ".objectstack");
1935
+ }
1936
+ function detectDriverFromUrl(dbUrl) {
1937
+ if (/^memory:\/\//i.test(dbUrl)) return "memory";
1938
+ if (/^(postgres(ql)?|pg):\/\//i.test(dbUrl)) return "postgres";
1939
+ if (/^mongodb(\+srv)?:\/\//i.test(dbUrl)) return "mongodb";
1940
+ if (/^wasm-sqlite:\/\//i.test(dbUrl)) return "sqlite-wasm";
1941
+ if (/\.wasm\.db$/i.test(dbUrl)) return "sqlite-wasm";
1942
+ if (/^file:/i.test(dbUrl)) return "sqlite";
1943
+ if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(dbUrl)) return "sqlite";
1944
+ throw new Error(
1945
+ `[StandaloneStack] Unsupported database URL scheme: ${dbUrl}. Supported schemes: memory://, postgres://, pg://, mongodb://, mongodb+srv://, file:`
1946
+ );
1947
+ }
1948
+ async function createStandaloneStack(config) {
1949
+ const cfg = StandaloneStackConfigSchema.parse(config ?? {});
1950
+ const { ObjectQLPlugin } = await import("@objectstack/objectql");
1951
+ const { MetadataPlugin } = await import("@objectstack/metadata");
1952
+ const { DriverPlugin: DriverPlugin2 } = await Promise.resolve().then(() => (init_driver_plugin(), driver_plugin_exports));
1953
+ const { AppPlugin: AppPlugin2 } = await Promise.resolve().then(() => (init_app_plugin(), app_plugin_exports));
1954
+ const cwd = process.cwd();
1955
+ const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? "proj_local";
1956
+ const artifactPathInput = cfg.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? (0, import_node_path3.resolve)(cwd, "dist/objectstack.json");
1957
+ const artifactPath = isHttpUrl(artifactPathInput) ? artifactPathInput : artifactPathInput.startsWith("/") ? artifactPathInput : (0, import_node_path3.resolve)(cwd, artifactPathInput);
1958
+ const dbUrl = cfg.databaseUrl ?? (0, import_types2.readEnvWithDeprecation)("OS_DATABASE_URL", "DATABASE_URL")?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? (process.env.OS_HOME?.trim() ? `file:${(0, import_node_path3.resolve)(resolveObjectStackHome(), "data/standalone.db")}` : cfg.projectRoot ? `file:${(0, import_node_path3.resolve)(cfg.projectRoot, ".objectstack/data/standalone.db")}` : `file:${(0, import_node_path3.resolve)(resolveObjectStackHome(), "data/standalone.db")}`);
1959
+ const explicitDriver = cfg.databaseDriver ?? process.env.OS_DATABASE_DRIVER?.trim();
1960
+ const dbDriver = explicitDriver ?? detectDriverFromUrl(dbUrl);
1961
+ let driverPlugin;
1962
+ if (dbDriver === "memory") {
1963
+ const { InMemoryDriver } = await import("@objectstack/driver-memory");
1964
+ driverPlugin = new DriverPlugin2(new InMemoryDriver());
1965
+ } else if (dbDriver === "postgres") {
1966
+ const { SqlDriver } = await import("@objectstack/driver-sql");
1967
+ driverPlugin = new DriverPlugin2(
1968
+ new SqlDriver({
1969
+ client: "pg",
1970
+ connection: dbUrl,
1971
+ pool: { min: 0, max: 5 }
1972
+ })
1973
+ );
1974
+ } else if (dbDriver === "mongodb") {
1975
+ let MongoDBDriver;
1976
+ try {
1977
+ ({ MongoDBDriver } = await import("@objectstack/driver-mongodb"));
1978
+ } catch (err) {
1979
+ throw new Error(
1980
+ `[StandaloneStack] mongodb URL detected but @objectstack/driver-mongodb is not installed. Add it as a dependency or pass an explicit driverPlugin. (${err?.message ?? err})`
1981
+ );
1982
+ }
1983
+ driverPlugin = new DriverPlugin2(new MongoDBDriver({ url: dbUrl }));
1984
+ } else if (dbDriver === "sqlite-wasm") {
1985
+ const { SqliteWasmDriver } = await import("@objectstack/driver-sqlite-wasm");
1986
+ const filename = dbUrl.replace(/^wasm-sqlite:(\/\/)?/i, "").replace(/^file:(\/\/)?/i, "");
1987
+ if (filename && filename !== ":memory:") {
1988
+ (0, import_node_fs2.mkdirSync)((0, import_node_path3.resolve)(filename, ".."), { recursive: true });
1989
+ }
1990
+ driverPlugin = new DriverPlugin2(
1991
+ new SqliteWasmDriver({
1992
+ filename: filename || ":memory:",
1993
+ persist: filename && filename !== ":memory:" ? "on-write" : void 0
1994
+ })
1995
+ );
1996
+ } else {
1997
+ const { SqlDriver } = await import("@objectstack/driver-sql");
1998
+ const filename = dbUrl.replace(/^file:(\/\/)?/, "");
1999
+ if (!filename || /^[a-z][a-z0-9+.-]*:\/\//i.test(filename)) {
2000
+ throw new Error(
2001
+ `[StandaloneStack] sqlite driver was selected but the URL does not look like a file path: "${dbUrl}". Use file:/path/to/db.sqlite, or set OS_DATABASE_DRIVER explicitly.`
2002
+ );
2003
+ }
2004
+ (0, import_node_fs2.mkdirSync)((0, import_node_path3.resolve)(filename, ".."), { recursive: true });
2005
+ driverPlugin = new DriverPlugin2(
2006
+ new SqlDriver({
2007
+ client: "better-sqlite3",
2008
+ connection: { filename },
2009
+ useNullAsDefault: true
2010
+ })
2011
+ );
2012
+ }
2013
+ const artifactBundle = await loadArtifactBundle(artifactPath, {
2014
+ tag: "[StandaloneStack]",
2015
+ unwrapEnvelope: true
2016
+ });
2017
+ if (artifactBundle) {
2018
+ const flowsCount = Array.isArray(artifactBundle?.flows) ? artifactBundle.flows.length : "n/a";
2019
+ console.warn(
2020
+ `[StandaloneStack] artifact loaded: path=${artifactPath} keys=${Object.keys(artifactBundle).join(",")} flows=${flowsCount}`
2021
+ );
2022
+ }
2023
+ const plugins = [
2024
+ driverPlugin,
2025
+ new MetadataPlugin({
2026
+ // Source-file scanner OFF — declarative metadata is loaded
2027
+ // from the compiled artifact, not from yaml/json files on
2028
+ // disk. Scanning would also recursively watch the project
2029
+ // root (incl. node_modules), which is expensive and prone
2030
+ // to EMFILE.
2031
+ watch: false,
2032
+ // Artifact-file HMR ON in non-production so edits to
2033
+ // `*.view.ts` / `*.flow.ts` (which the CLI dev-mode watcher
2034
+ // recompiles into `dist/objectstack.json`) are picked up by
2035
+ // the running server WITHOUT requiring a manual restart.
2036
+ // Uses polling under the hood (see plugin.ts) to avoid
2037
+ // `fs.watch` EMFILE on macOS / busy dev hosts.
2038
+ artifactWatch: process.env.NODE_ENV !== "production",
2039
+ environmentId,
2040
+ artifactSource: { mode: "local-file", path: artifactPath }
2041
+ }),
2042
+ new ObjectQLPlugin({ environmentId })
2043
+ ];
2044
+ if (artifactBundle) plugins.push(new AppPlugin2(artifactBundle));
2045
+ const requires = Array.isArray(artifactBundle?.requires) ? artifactBundle.requires.filter((c) => typeof c === "string") : void 0;
2046
+ const objects = Array.isArray(artifactBundle?.objects) ? artifactBundle.objects : void 0;
2047
+ const manifest = artifactBundle?.manifest;
2048
+ return {
2049
+ plugins,
2050
+ api: {
2051
+ enableProjectScoping: false,
2052
+ projectResolution: "none"
2053
+ },
2054
+ ...requires ? { requires } : {},
2055
+ ...objects ? { objects } : {},
2056
+ ...manifest ? { manifest } : {}
2057
+ };
2058
+ }
2059
+ var import_node_path3, import_node_fs2, import_node_os, import_zod, import_types2, StandaloneStackConfigSchema;
2060
+ var init_standalone_stack = __esm({
2061
+ "src/standalone-stack.ts"() {
2062
+ "use strict";
2063
+ import_node_path3 = require("path");
2064
+ import_node_fs2 = require("fs");
2065
+ import_node_os = require("os");
2066
+ import_zod = require("zod");
2067
+ import_types2 = require("@objectstack/types");
2068
+ init_load_artifact_bundle();
2069
+ StandaloneStackConfigSchema = import_zod.z.object({
2070
+ databaseUrl: import_zod.z.string().optional(),
2071
+ databaseAuthToken: import_zod.z.string().optional(),
2072
+ databaseDriver: import_zod.z.enum(["sqlite", "sqlite-wasm", "memory", "postgres", "mongodb"]).optional(),
2073
+ environmentId: import_zod.z.string().optional(),
2074
+ artifactPath: import_zod.z.string().optional(),
2075
+ /**
2076
+ * Project root directory. When set (typically by the CLI after locating
2077
+ * `objectstack.config.ts`), the default sqlite database is placed under
2078
+ * `<projectRoot>/.objectstack/data/standalone.db` instead of the global
2079
+ * `~/.objectstack/data/standalone.db`. This keeps per-project data
2080
+ * scoped to the project folder so different examples / apps don't
2081
+ * share a single database by accident.
2082
+ *
2083
+ * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
2084
+ * precedence over this default.
2085
+ */
2086
+ projectRoot: import_zod.z.string().optional()
2087
+ });
2088
+ }
2089
+ });
2090
+
1861
2091
  // src/cloud/platform-sso.ts
1862
2092
  var platform_sso_exports = {};
1863
2093
  __export(platform_sso_exports, {
@@ -2249,6 +2479,7 @@ __export(index_exports, {
2249
2479
  SandboxError: () => SandboxError,
2250
2480
  SeedLoaderService: () => SeedLoaderService,
2251
2481
  UnimplementedScriptRunner: () => UnimplementedScriptRunner,
2482
+ _resetEnvDeprecationWarnings: () => import_types6._resetEnvDeprecationWarnings,
2252
2483
  actionBodyRunnerFactory: () => actionBodyRunnerFactory,
2253
2484
  backfillPlatformSsoClients: () => backfillPlatformSsoClients,
2254
2485
  buildPlatformSsoRedirectUri: () => buildPlatformSsoRedirectUri,
@@ -2273,6 +2504,7 @@ __export(index_exports, {
2273
2504
  mergeRuntimeModule: () => mergeRuntimeModule,
2274
2505
  parseTraceparent: () => parseTraceparent,
2275
2506
  readArtifactSource: () => readArtifactSource,
2507
+ readEnvWithDeprecation: () => import_types6.readEnvWithDeprecation,
2276
2508
  resolveCloudUrl: () => resolveCloudUrl,
2277
2509
  resolveDefaultArtifactPath: () => resolveDefaultArtifactPath,
2278
2510
  resolveErrorReporter: () => resolveErrorReporter,
@@ -2330,172 +2562,19 @@ var Runtime = class {
2330
2562
  }
2331
2563
  };
2332
2564
 
2333
- // src/standalone-stack.ts
2334
- var import_node_path2 = require("path");
2335
- var import_node_fs = require("fs");
2336
- var import_node_os = require("os");
2337
- var import_zod = require("zod");
2338
- init_load_artifact_bundle();
2339
- function resolveObjectStackHome() {
2340
- const raw = process.env.OS_HOME?.trim();
2341
- if (raw && raw.length > 0) {
2342
- if (raw.startsWith("~")) return (0, import_node_path2.resolve)((0, import_node_os.homedir)(), raw.slice(1).replace(/^[/\\]/, ""));
2343
- return (0, import_node_path2.resolve)(raw);
2344
- }
2345
- return (0, import_node_path2.resolve)((0, import_node_os.homedir)(), ".objectstack");
2346
- }
2347
- var StandaloneStackConfigSchema = import_zod.z.object({
2348
- databaseUrl: import_zod.z.string().optional(),
2349
- databaseAuthToken: import_zod.z.string().optional(),
2350
- databaseDriver: import_zod.z.enum(["sqlite", "sqlite-wasm", "memory", "postgres", "mongodb"]).optional(),
2351
- environmentId: import_zod.z.string().optional(),
2352
- artifactPath: import_zod.z.string().optional(),
2353
- /**
2354
- * Project root directory. When set (typically by the CLI after locating
2355
- * `objectstack.config.ts`), the default sqlite database is placed under
2356
- * `<projectRoot>/.objectstack/data/standalone.db` instead of the global
2357
- * `~/.objectstack/data/standalone.db`. This keeps per-project data
2358
- * scoped to the project folder so different examples / apps don't
2359
- * share a single database by accident.
2360
- *
2361
- * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
2362
- * precedence over this default.
2363
- */
2364
- projectRoot: import_zod.z.string().optional()
2365
- });
2366
- function detectDriverFromUrl(dbUrl) {
2367
- if (/^memory:\/\//i.test(dbUrl)) return "memory";
2368
- if (/^(postgres(ql)?|pg):\/\//i.test(dbUrl)) return "postgres";
2369
- if (/^mongodb(\+srv)?:\/\//i.test(dbUrl)) return "mongodb";
2370
- if (/^wasm-sqlite:\/\//i.test(dbUrl)) return "sqlite-wasm";
2371
- if (/\.wasm\.db$/i.test(dbUrl)) return "sqlite-wasm";
2372
- if (/^file:/i.test(dbUrl)) return "sqlite";
2373
- if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(dbUrl)) return "sqlite";
2374
- throw new Error(
2375
- `[StandaloneStack] Unsupported database URL scheme: ${dbUrl}. Supported schemes: memory://, postgres://, pg://, mongodb://, mongodb+srv://, file:`
2376
- );
2377
- }
2378
- async function createStandaloneStack(config) {
2379
- const cfg = StandaloneStackConfigSchema.parse(config ?? {});
2380
- const { ObjectQLPlugin } = await import("@objectstack/objectql");
2381
- const { MetadataPlugin } = await import("@objectstack/metadata");
2382
- const { DriverPlugin: DriverPlugin2 } = await Promise.resolve().then(() => (init_driver_plugin(), driver_plugin_exports));
2383
- const { AppPlugin: AppPlugin2 } = await Promise.resolve().then(() => (init_app_plugin(), app_plugin_exports));
2384
- const cwd = process.cwd();
2385
- const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? "proj_local";
2386
- const artifactPathInput = cfg.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? (0, import_node_path2.resolve)(cwd, "dist/objectstack.json");
2387
- const artifactPath = isHttpUrl(artifactPathInput) ? artifactPathInput : artifactPathInput.startsWith("/") ? artifactPathInput : (0, import_node_path2.resolve)(cwd, artifactPathInput);
2388
- const dbUrl = cfg.databaseUrl ?? process.env.OS_DATABASE_URL?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? (process.env.OS_HOME?.trim() ? `file:${(0, import_node_path2.resolve)(resolveObjectStackHome(), "data/standalone.db")}` : cfg.projectRoot ? `file:${(0, import_node_path2.resolve)(cfg.projectRoot, ".objectstack/data/standalone.db")}` : `file:${(0, import_node_path2.resolve)(resolveObjectStackHome(), "data/standalone.db")}`);
2389
- const explicitDriver = cfg.databaseDriver ?? process.env.OS_DATABASE_DRIVER?.trim();
2390
- const dbDriver = explicitDriver ?? detectDriverFromUrl(dbUrl);
2391
- let driverPlugin;
2392
- if (dbDriver === "memory") {
2393
- const { InMemoryDriver } = await import("@objectstack/driver-memory");
2394
- driverPlugin = new DriverPlugin2(new InMemoryDriver());
2395
- } else if (dbDriver === "postgres") {
2396
- const { SqlDriver } = await import("@objectstack/driver-sql");
2397
- driverPlugin = new DriverPlugin2(
2398
- new SqlDriver({
2399
- client: "pg",
2400
- connection: dbUrl,
2401
- pool: { min: 0, max: 5 }
2402
- })
2403
- );
2404
- } else if (dbDriver === "mongodb") {
2405
- let MongoDBDriver;
2406
- try {
2407
- ({ MongoDBDriver } = await import("@objectstack/driver-mongodb"));
2408
- } catch (err) {
2409
- throw new Error(
2410
- `[StandaloneStack] mongodb URL detected but @objectstack/driver-mongodb is not installed. Add it as a dependency or pass an explicit driverPlugin. (${err?.message ?? err})`
2411
- );
2412
- }
2413
- driverPlugin = new DriverPlugin2(new MongoDBDriver({ url: dbUrl }));
2414
- } else if (dbDriver === "sqlite-wasm") {
2415
- const { SqliteWasmDriver } = await import("@objectstack/driver-sqlite-wasm");
2416
- const filename = dbUrl.replace(/^wasm-sqlite:(\/\/)?/i, "").replace(/^file:(\/\/)?/i, "");
2417
- if (filename && filename !== ":memory:") {
2418
- (0, import_node_fs.mkdirSync)((0, import_node_path2.resolve)(filename, ".."), { recursive: true });
2419
- }
2420
- driverPlugin = new DriverPlugin2(
2421
- new SqliteWasmDriver({
2422
- filename: filename || ":memory:",
2423
- persist: filename && filename !== ":memory:" ? "on-write" : void 0
2424
- })
2425
- );
2426
- } else {
2427
- const { SqlDriver } = await import("@objectstack/driver-sql");
2428
- const filename = dbUrl.replace(/^file:(\/\/)?/, "");
2429
- if (!filename || /^[a-z][a-z0-9+.-]*:\/\//i.test(filename)) {
2430
- throw new Error(
2431
- `[StandaloneStack] sqlite driver was selected but the URL does not look like a file path: "${dbUrl}". Use file:/path/to/db.sqlite, or set OS_DATABASE_DRIVER explicitly.`
2432
- );
2433
- }
2434
- (0, import_node_fs.mkdirSync)((0, import_node_path2.resolve)(filename, ".."), { recursive: true });
2435
- driverPlugin = new DriverPlugin2(
2436
- new SqlDriver({
2437
- client: "better-sqlite3",
2438
- connection: { filename },
2439
- useNullAsDefault: true
2440
- })
2441
- );
2442
- }
2443
- const artifactBundle = await loadArtifactBundle(artifactPath, {
2444
- tag: "[StandaloneStack]",
2445
- unwrapEnvelope: true
2446
- });
2447
- if (artifactBundle) {
2448
- const flowsCount = Array.isArray(artifactBundle?.flows) ? artifactBundle.flows.length : "n/a";
2449
- console.warn(
2450
- `[StandaloneStack] artifact loaded: path=${artifactPath} keys=${Object.keys(artifactBundle).join(",")} flows=${flowsCount}`
2451
- );
2452
- }
2453
- const plugins = [
2454
- driverPlugin,
2455
- new MetadataPlugin({
2456
- // Source-file scanner OFF — declarative metadata is loaded
2457
- // from the compiled artifact, not from yaml/json files on
2458
- // disk. Scanning would also recursively watch the project
2459
- // root (incl. node_modules), which is expensive and prone
2460
- // to EMFILE.
2461
- watch: false,
2462
- // Artifact-file HMR ON in non-production so edits to
2463
- // `*.view.ts` / `*.flow.ts` (which the CLI dev-mode watcher
2464
- // recompiles into `dist/objectstack.json`) are picked up by
2465
- // the running server WITHOUT requiring a manual restart.
2466
- // Uses polling under the hood (see plugin.ts) to avoid
2467
- // `fs.watch` EMFILE on macOS / busy dev hosts.
2468
- artifactWatch: process.env.NODE_ENV !== "production",
2469
- environmentId,
2470
- artifactSource: { mode: "local-file", path: artifactPath }
2471
- }),
2472
- new ObjectQLPlugin({ environmentId })
2473
- ];
2474
- if (artifactBundle) plugins.push(new AppPlugin2(artifactBundle));
2475
- const requires = Array.isArray(artifactBundle?.requires) ? artifactBundle.requires.filter((c) => typeof c === "string") : void 0;
2476
- const objects = Array.isArray(artifactBundle?.objects) ? artifactBundle.objects : void 0;
2477
- const manifest = artifactBundle?.manifest;
2478
- return {
2479
- plugins,
2480
- api: {
2481
- enableProjectScoping: false,
2482
- projectResolution: "none"
2483
- },
2484
- ...requires ? { requires } : {},
2485
- ...objects ? { objects } : {},
2486
- ...manifest ? { manifest } : {}
2487
- };
2488
- }
2565
+ // src/index.ts
2566
+ init_standalone_stack();
2489
2567
 
2490
2568
  // src/default-host.ts
2491
- var import_node_path3 = require("path");
2492
- var import_node_fs2 = require("fs");
2569
+ var import_node_path4 = require("path");
2570
+ var import_node_fs3 = require("fs");
2571
+ init_standalone_stack();
2493
2572
  init_load_artifact_bundle();
2494
2573
  function resolveDefaultArtifactPath(explicitPath, cwd = process.cwd()) {
2495
- const candidate = explicitPath ?? process.env.OS_ARTIFACT_PATH ?? (0, import_node_path3.resolve)(cwd, "dist/objectstack.json");
2574
+ const candidate = explicitPath ?? process.env.OS_ARTIFACT_PATH ?? (0, import_node_path4.resolve)(cwd, "dist/objectstack.json");
2496
2575
  if (isHttpUrl(candidate)) return candidate;
2497
2576
  if (explicitPath || process.env.OS_ARTIFACT_PATH) return candidate;
2498
- return (0, import_node_fs2.existsSync)(candidate) ? candidate : void 0;
2577
+ return (0, import_node_fs3.existsSync)(candidate) ? candidate : void 0;
2499
2578
  }
2500
2579
  async function createDefaultHostConfig(options = {}) {
2501
2580
  const { requireArtifact = true, ...standaloneOpts } = options;
@@ -2507,10 +2586,10 @@ async function createDefaultHostConfig(options = {}) {
2507
2586
  }
2508
2587
  if (!resolvedArtifact && !requireArtifact) {
2509
2588
  const home = resolveObjectStackHome();
2510
- const stubPath = (0, import_node_path3.resolve)(home, "dist/objectstack.json");
2511
- if (!(0, import_node_fs2.existsSync)(stubPath)) {
2512
- (0, import_node_fs2.mkdirSync)((0, import_node_path3.resolve)(stubPath, ".."), { recursive: true });
2513
- (0, import_node_fs2.writeFileSync)(
2589
+ const stubPath = (0, import_node_path4.resolve)(home, "dist/objectstack.json");
2590
+ if (!(0, import_node_fs3.existsSync)(stubPath)) {
2591
+ (0, import_node_fs3.mkdirSync)((0, import_node_path4.resolve)(stubPath, ".."), { recursive: true });
2592
+ (0, import_node_fs3.writeFileSync)(
2514
2593
  stubPath,
2515
2594
  JSON.stringify(
2516
2595
  {
@@ -2548,8 +2627,10 @@ init_seed_loader();
2548
2627
 
2549
2628
  // src/http-dispatcher.ts
2550
2629
  var import_core2 = require("@objectstack/core");
2630
+ var import_types3 = require("@objectstack/types");
2551
2631
  var import_system = require("@objectstack/spec/system");
2552
2632
  var import_shared = require("@objectstack/spec/shared");
2633
+ init_package_state_store();
2553
2634
 
2554
2635
  // src/security/resolve-execution-context.ts
2555
2636
  function readHeader(headers, name) {
@@ -3404,7 +3485,7 @@ var _HttpDispatcher = class _HttpDispatcher {
3404
3485
  if (protocol && typeof protocol.saveMetaItem === "function") {
3405
3486
  try {
3406
3487
  const organizationId = await this.resolveActiveOrganizationId(_context);
3407
- const result = await protocol.saveMetaItem({ type, name, item: body, organizationId });
3488
+ const result = await protocol.saveMetaItem({ type, name, item: body, organizationId, ...packageId ? { packageId } : {} });
3408
3489
  return { handled: true, response: this.success(result) };
3409
3490
  } catch (e) {
3410
3491
  return { handled: true, response: this.error(e.message, 400) };
@@ -3744,12 +3825,22 @@ var _HttpDispatcher = class _HttpDispatcher {
3744
3825
  const id = decodeURIComponent(parts[0]);
3745
3826
  const pkg = registry.enablePackage(id);
3746
3827
  if (!pkg) return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3828
+ try {
3829
+ setPackageDisabled(_context?.environmentId, id, false);
3830
+ } catch (err) {
3831
+ console.warn("[handlePackages] failed to persist enable state", { id, error: err?.message });
3832
+ }
3747
3833
  return { handled: true, response: this.success(pkg) };
3748
3834
  }
3749
3835
  if (parts.length === 2 && parts[1] === "disable" && m === "PATCH") {
3750
3836
  const id = decodeURIComponent(parts[0]);
3751
3837
  const pkg = registry.disablePackage(id);
3752
3838
  if (!pkg) return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3839
+ try {
3840
+ setPackageDisabled(_context?.environmentId, id, true);
3841
+ } catch (err) {
3842
+ console.warn("[handlePackages] failed to persist disable state", { id, error: err?.message });
3843
+ }
3753
3844
  return { handled: true, response: this.success(pkg) };
3754
3845
  }
3755
3846
  if (parts.length === 2 && parts[1] === "publish" && m === "POST") {
@@ -3770,6 +3861,14 @@ var _HttpDispatcher = class _HttpDispatcher {
3770
3861
  }
3771
3862
  return { handled: true, response: this.error("Metadata service not available", 503) };
3772
3863
  }
3864
+ if (parts.length === 2 && parts[1] === "export" && m === "GET") {
3865
+ const id = decodeURIComponent(parts[0]);
3866
+ const manifest = await this.assemblePackageManifest(id, registry, _context);
3867
+ if (!manifest) {
3868
+ return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3869
+ }
3870
+ return { handled: true, response: this.success(manifest) };
3871
+ }
3773
3872
  if (parts.length === 1 && m === "GET") {
3774
3873
  const id = decodeURIComponent(parts[0]);
3775
3874
  const pkg = registry.getPackage(id);
@@ -3787,6 +3886,83 @@ var _HttpDispatcher = class _HttpDispatcher {
3787
3886
  }
3788
3887
  return { handled: false };
3789
3888
  }
3889
+ /**
3890
+ * Assemble a portable, offline-installable package manifest from the
3891
+ * `sys_metadata` overlay rows bound to `packageId`.
3892
+ *
3893
+ * The resulting shape mirrors what `marketplace-install-local` →
3894
+ * `manifestService.register()` → `engine.registerApp()` consumes:
3895
+ * `{ id, name, version, objects:[…], views:[…], flows:[…], … }`
3896
+ * where each category key is the PLURAL manifest name and its value is
3897
+ * an array of clean metadata bodies (provenance decorations stripped).
3898
+ *
3899
+ * Only the metadata categories that `registerApp` can actually consume
3900
+ * are exported. `datasources` and `emailTemplates` are intentionally
3901
+ * excluded (not registered by the import path). `tools` / `skills` ARE
3902
+ * round-tripped: they are registered by `registerApp` on import and
3903
+ * surfaced by `getMetaItems('tool' | 'skill')` on export.
3904
+ *
3905
+ * @returns the manifest object, or `null` if the package id is unknown
3906
+ * AND has no overlay-authored metadata.
3907
+ */
3908
+ async assemblePackageManifest(packageId, registry, context) {
3909
+ const protocol = await this.resolveService("protocol");
3910
+ if (!protocol || typeof protocol.getMetaItems !== "function") return null;
3911
+ const organizationId = await this.resolveActiveOrganizationId(context);
3912
+ const PROVENANCE_KEYS = /* @__PURE__ */ new Set([
3913
+ "_packageId",
3914
+ "_packageVersionId",
3915
+ "_provenance",
3916
+ "_state",
3917
+ "_version",
3918
+ "_organizationId",
3919
+ "_source",
3920
+ "_id",
3921
+ "_rowId"
3922
+ ]);
3923
+ const clean = (item) => {
3924
+ if (!item || typeof item !== "object") return item;
3925
+ const out = {};
3926
+ for (const [k, v] of Object.entries(item)) {
3927
+ if (k.startsWith("_") || PROVENANCE_KEYS.has(k)) continue;
3928
+ out[k] = v;
3929
+ }
3930
+ return out;
3931
+ };
3932
+ const exportPluralKeys = Object.keys(import_shared.PLURAL_TO_SINGULAR).filter(
3933
+ (k) => k !== "datasources" && k !== "emailTemplates"
3934
+ );
3935
+ const manifest = {};
3936
+ let total = 0;
3937
+ for (const plural of exportPluralKeys) {
3938
+ const singular = import_shared.PLURAL_TO_SINGULAR[plural];
3939
+ let items = [];
3940
+ try {
3941
+ const res = await protocol.getMetaItems({ type: singular, packageId, organizationId });
3942
+ items = Array.isArray(res?.items) ? res.items : [];
3943
+ } catch {
3944
+ continue;
3945
+ }
3946
+ if (items.length === 0) continue;
3947
+ manifest[plural] = items.map(clean);
3948
+ total += items.length;
3949
+ }
3950
+ const pkg = (() => {
3951
+ try {
3952
+ return registry?.getPackage?.(packageId);
3953
+ } catch {
3954
+ return void 0;
3955
+ }
3956
+ })();
3957
+ if (total === 0 && !pkg) return null;
3958
+ manifest.id = packageId;
3959
+ manifest.name = pkg?.manifest?.name ?? pkg?.name ?? packageId;
3960
+ manifest.version = pkg?.manifest?.version ?? pkg?.version ?? "1.0.0";
3961
+ if (pkg?.manifest?.label ?? pkg?.label) {
3962
+ manifest.label = pkg?.manifest?.label ?? pkg?.label;
3963
+ }
3964
+ return manifest;
3965
+ }
3790
3966
  /**
3791
3967
  * Cloud / Environment Control-Plane routes.
3792
3968
  *
@@ -4038,7 +4214,7 @@ var _HttpDispatcher = class _HttpDispatcher {
4038
4214
  }
4039
4215
  }
4040
4216
  if (parts.length === 3 && parts[0] === "admin" && parts[1] === "platform-sso" && parts[2] === "backfill" && m === "POST") {
4041
- const baseSecret = (process.env.OS_AUTH_SECRET ?? process.env.AUTH_SECRET ?? "").trim();
4217
+ const baseSecret = ((0, import_types3.readEnvWithDeprecation)("OS_AUTH_SECRET", ["AUTH_SECRET", "BETTER_AUTH_SECRET"]) ?? "").trim();
4042
4218
  if (!baseSecret) {
4043
4219
  return { handled: true, response: this.error("OS_AUTH_SECRET not configured on this worker", 503) };
4044
4220
  }
@@ -4228,7 +4404,7 @@ var _HttpDispatcher = class _HttpDispatcher {
4228
4404
  });
4229
4405
  try {
4230
4406
  const { seedPlatformSsoClient: seedPlatformSsoClient2 } = await Promise.resolve().then(() => (init_platform_sso(), platform_sso_exports));
4231
- const baseSecret = (process.env.OS_AUTH_SECRET ?? process.env.AUTH_SECRET ?? "").trim();
4407
+ const baseSecret = ((0, import_types3.readEnvWithDeprecation)("OS_AUTH_SECRET", ["AUTH_SECRET", "BETTER_AUTH_SECRET"]) ?? "").trim();
4232
4408
  if (baseSecret) {
4233
4409
  await seedPlatformSsoClient2({
4234
4410
  ql,
@@ -6369,6 +6545,14 @@ function createDispatcherPlugin(config = {}) {
6369
6545
  errorResponse(err, res);
6370
6546
  }
6371
6547
  });
6548
+ server.get(`${prefix}/packages/:id/export`, async (req, res) => {
6549
+ try {
6550
+ const result = await dispatcher.handlePackages(`/${req.params.id}/export`, "GET", {}, req.query, { request: req });
6551
+ sendResult(result, res);
6552
+ } catch (err) {
6553
+ errorResponse(err, res);
6554
+ }
6555
+ });
6372
6556
  server.get(`${prefix}/packages/:id`, async (req, res) => {
6373
6557
  try {
6374
6558
  const result = await dispatcher.handlePackages(`/${req.params.id}`, "GET", {}, req.query, { request: req });
@@ -7476,7 +7660,7 @@ var ArtifactApiClient = class {
7476
7660
  };
7477
7661
 
7478
7662
  // src/cloud/artifact-environment-registry.ts
7479
- var import_node_path4 = require("path");
7663
+ var import_node_path5 = require("path");
7480
7664
  var ArtifactEnvironmentRegistry = class {
7481
7665
  constructor(config) {
7482
7666
  this.hostnameCache = /* @__PURE__ */ new Map();
@@ -7648,7 +7832,7 @@ async function createDriver(driverType, databaseUrl, authToken) {
7648
7832
  case "memory": {
7649
7833
  const { InMemoryDriver } = await import("@objectstack/driver-memory");
7650
7834
  const dbName = databaseUrl.replace(/^memory:\/\//, "").trim();
7651
- const filePath = dbName ? (0, import_node_path4.resolve)(process.cwd(), ".objectstack/data/projects", `${dbName}.json`) : void 0;
7835
+ const filePath = dbName ? (0, import_node_path5.resolve)(process.cwd(), ".objectstack/data/projects", `${dbName}.json`) : void 0;
7652
7836
  return new InMemoryDriver({
7653
7837
  persistence: filePath ? { type: "file", path: filePath } : "file"
7654
7838
  });
@@ -7686,6 +7870,7 @@ async function createDriver(driverType, databaseUrl, authToken) {
7686
7870
  // src/cloud/artifact-kernel-factory.ts
7687
7871
  var import_node_crypto2 = require("crypto");
7688
7872
  var import_core3 = require("@objectstack/core");
7873
+ var import_types4 = require("@objectstack/types");
7689
7874
  init_driver_plugin();
7690
7875
  init_app_plugin();
7691
7876
 
@@ -7825,7 +8010,7 @@ var ArtifactKernelFactory = class {
7825
8010
  this.envRegistry = config.envRegistry;
7826
8011
  this.logger = config.logger ?? console;
7827
8012
  this.kernelConfig = config.kernelConfig;
7828
- this.authBaseSecret = (config.authBaseSecret ?? process.env.OS_AUTH_SECRET ?? process.env.AUTH_SECRET ?? "").trim();
8013
+ this.authBaseSecret = (config.authBaseSecret ?? (0, import_types4.readEnvWithDeprecation)("OS_AUTH_SECRET", ["AUTH_SECRET", "BETTER_AUTH_SECRET"]) ?? "").trim();
7829
8014
  }
7830
8015
  async create(environmentId) {
7831
8016
  let cached = this.envRegistry.peekById(environmentId);
@@ -7938,7 +8123,7 @@ var ArtifactKernelFactory = class {
7938
8123
  this.logger.warn?.("[ArtifactKernelFactory] OS_AUTH_SECRET not set \u2014 per-project AuthPlugin skipped (auth endpoints will return 404)", { environmentId });
7939
8124
  }
7940
8125
  try {
7941
- const multiTenant = String(process.env.OS_MULTI_TENANT ?? "false").toLowerCase() !== "false";
8126
+ const multiTenant = String((0, import_types4.readEnvWithDeprecation)("OS_MULTI_ORG_ENABLED", "OS_MULTI_TENANT") ?? "false").toLowerCase() !== "false";
7942
8127
  if (multiTenant) {
7943
8128
  try {
7944
8129
  const { OrgScopingPlugin } = await import("@objectstack/plugin-org-scoping");
@@ -8464,7 +8649,7 @@ var AuthProxyPlugin = class {
8464
8649
  };
8465
8650
 
8466
8651
  // src/cloud/cloud-url.ts
8467
- var DEFAULT_CLOUD_URL = "https://cloud.objectos.app";
8652
+ var DEFAULT_CLOUD_URL = "https://cloud.objectos.ai";
8468
8653
  function resolveCloudUrl(explicit) {
8469
8654
  const raw = (explicit ?? process.env.OS_CLOUD_URL ?? "").trim();
8470
8655
  const lower = raw.toLowerCase();
@@ -8886,11 +9071,11 @@ var RuntimeConfigPlugin = class {
8886
9071
 
8887
9072
  // src/cloud/file-artifact-api-client.ts
8888
9073
  var import_promises2 = require("fs/promises");
8889
- var import_node_path5 = require("path");
9074
+ var import_node_path6 = require("path");
8890
9075
  var FileArtifactApiClient = class {
8891
9076
  constructor(config = {}) {
8892
9077
  const cwd = process.cwd();
8893
- this.artifactPath = (0, import_node_path5.resolve)(
9078
+ this.artifactPath = (0, import_node_path6.resolve)(
8894
9079
  cwd,
8895
9080
  config.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? "dist/objectstack.json"
8896
9081
  );
@@ -8986,7 +9171,7 @@ var FileArtifactApiClient = class {
8986
9171
  }
8987
9172
  defaultLocalSqliteRuntime() {
8988
9173
  const cwd = process.cwd();
8989
- const dbPath = (0, import_node_path5.resolve)(cwd, ".objectstack/data", `${this.environmentId}.db`);
9174
+ const dbPath = (0, import_node_path6.resolve)(cwd, ".objectstack/data", `${this.environmentId}.db`);
8990
9175
  return {
8991
9176
  databaseDriver: "sqlite",
8992
9177
  databaseUrl: `file:${dbPath}`
@@ -9139,8 +9324,9 @@ async function createObjectOSStack(config) {
9139
9324
  }
9140
9325
 
9141
9326
  // src/cloud/marketplace-install-local-plugin.ts
9142
- var import_node_fs3 = require("fs");
9143
- var import_node_path6 = require("path");
9327
+ var import_node_fs4 = require("fs");
9328
+ var import_node_path7 = require("path");
9329
+ var import_types5 = require("@objectstack/types");
9144
9330
  var ROUTE_BASE = "/api/v1/marketplace/install-local";
9145
9331
  var DEFAULT_DIR = ".objectstack/installed-packages";
9146
9332
  function safeFilename(manifestId) {
@@ -9215,9 +9401,6 @@ var MarketplaceInstallLocalPlugin = class {
9215
9401
  }
9216
9402
  };
9217
9403
  this.handleInstall = async (c, ctx) => {
9218
- if (!this.cloudUrl) {
9219
- return c.json({ success: false, error: { code: "marketplace_unavailable", message: "OS_CLOUD_URL not configured." } }, 503);
9220
- }
9221
9404
  const userId = await this.requireAuthenticatedUser(c, ctx);
9222
9405
  if (!userId) {
9223
9406
  return c.json({ success: false, error: { code: "unauthorized", message: "Authentication required to install packages." } }, 401);
@@ -9227,69 +9410,87 @@ var MarketplaceInstallLocalPlugin = class {
9227
9410
  body = await c.req.json();
9228
9411
  } catch {
9229
9412
  }
9230
- const packageId = String(body?.packageId ?? "").trim();
9231
- const versionId = String(body?.versionId ?? "latest").trim() || "latest";
9232
- if (!packageId) {
9233
- return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
9234
- }
9235
- let payload;
9236
- const publicBase = resolveMarketplacePublicBaseUrl();
9237
- const fetchAttempts = [];
9238
- if (publicBase) {
9413
+ const inlineManifest = body?.manifest && typeof body.manifest === "object" ? body.manifest : null;
9414
+ let manifest;
9415
+ let resolvedVersionId;
9416
+ let version;
9417
+ let packageId;
9418
+ if (inlineManifest) {
9419
+ manifest = inlineManifest;
9420
+ packageId = String(manifest.id ?? manifest.name ?? "").trim();
9421
+ version = String(manifest.version ?? "unknown");
9422
+ resolvedVersionId = String(body?.versionId ?? version);
9423
+ if (!packageId) {
9424
+ return c.json({ success: false, error: { code: "invalid_manifest", message: 'Inline manifest must have an "id" or "name".' } }, 400);
9425
+ }
9426
+ } else {
9427
+ if (!this.cloudUrl) {
9428
+ return c.json({ success: false, error: { code: "marketplace_unavailable", message: "OS_CLOUD_URL not configured." } }, 503);
9429
+ }
9430
+ packageId = String(body?.packageId ?? "").trim();
9431
+ const versionId = String(body?.versionId ?? "latest").trim() || "latest";
9432
+ if (!packageId) {
9433
+ return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
9434
+ }
9435
+ let payload;
9436
+ const publicBase = resolveMarketplacePublicBaseUrl();
9437
+ const fetchAttempts = [];
9438
+ if (publicBase) {
9439
+ fetchAttempts.push({
9440
+ label: "public-r2",
9441
+ url: `${publicBase}/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest.json`
9442
+ });
9443
+ }
9239
9444
  fetchAttempts.push({
9240
- label: "public-r2",
9241
- url: `${publicBase}/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest.json`
9445
+ label: "cloud",
9446
+ url: `${this.cloudUrl}/api/v1/marketplace/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest`
9242
9447
  });
9243
- }
9244
- fetchAttempts.push({
9245
- label: "cloud",
9246
- url: `${this.cloudUrl}/api/v1/marketplace/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest`
9247
- });
9248
- let lastErrStatus = 0;
9249
- let lastErrText = "";
9250
- for (const attempt of fetchAttempts) {
9251
- try {
9252
- const resp = await fetch(attempt.url, { headers: { "Accept": "application/json" } });
9253
- if (!resp.ok) {
9254
- lastErrStatus = resp.status;
9255
- lastErrText = (await resp.text().catch(() => "")).slice(0, 200);
9256
- if (attempt.label === "public-r2" && resp.status === 404) {
9257
- ctx.logger?.info?.(`[MarketplaceInstallLocal] public-r2 miss for ${packageId}@${versionId}, falling back to cloud`);
9258
- continue;
9448
+ let lastErrStatus = 0;
9449
+ let lastErrText = "";
9450
+ for (const attempt of fetchAttempts) {
9451
+ try {
9452
+ const resp = await fetch(attempt.url, { headers: { "Accept": "application/json" } });
9453
+ if (!resp.ok) {
9454
+ lastErrStatus = resp.status;
9455
+ lastErrText = (await resp.text().catch(() => "")).slice(0, 200);
9456
+ if (attempt.label === "public-r2" && resp.status === 404) {
9457
+ ctx.logger?.info?.(`[MarketplaceInstallLocal] public-r2 miss for ${packageId}@${versionId}, falling back to cloud`);
9458
+ continue;
9459
+ }
9460
+ if (attempt.label === "public-r2" && resp.status >= 500) {
9461
+ ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 ${resp.status}, falling back to cloud`);
9462
+ continue;
9463
+ }
9464
+ break;
9259
9465
  }
9260
- if (attempt.label === "public-r2" && resp.status >= 500) {
9261
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 ${resp.status}, falling back to cloud`);
9466
+ payload = await resp.json();
9467
+ lastErrStatus = 0;
9468
+ break;
9469
+ } catch (err) {
9470
+ if (attempt.label === "public-r2") {
9471
+ ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 fetch error: ${err?.message ?? err}, falling back to cloud`);
9262
9472
  continue;
9263
9473
  }
9264
- break;
9265
- }
9266
- payload = await resp.json();
9267
- lastErrStatus = 0;
9268
- break;
9269
- } catch (err) {
9270
- if (attempt.label === "public-r2") {
9271
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 fetch error: ${err?.message ?? err}, falling back to cloud`);
9272
- continue;
9474
+ return c.json({
9475
+ success: false,
9476
+ error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
9477
+ }, 502);
9273
9478
  }
9479
+ }
9480
+ if (!payload) {
9274
9481
  return c.json({
9275
9482
  success: false,
9276
- error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
9277
- }, 502);
9483
+ error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
9484
+ }, lastErrStatus === 404 ? 404 : 502);
9278
9485
  }
9486
+ const data = payload?.data ?? payload;
9487
+ manifest = data?.manifest;
9488
+ resolvedVersionId = String(data?.version_id ?? versionId);
9489
+ version = String(data?.version ?? "unknown");
9279
9490
  }
9280
- if (!payload) {
9281
- return c.json({
9282
- success: false,
9283
- error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
9284
- }, lastErrStatus === 404 ? 404 : 502);
9285
- }
9286
- const data = payload?.data ?? payload;
9287
- const manifest = data?.manifest;
9288
- const resolvedVersionId = String(data?.version_id ?? versionId);
9289
- const version = String(data?.version ?? "unknown");
9290
9491
  const manifestId = String(manifest?.id ?? manifest?.name ?? "");
9291
9492
  if (!manifest || !manifestId) {
9292
- return c.json({ success: false, error: { code: "invalid_manifest", message: "Cloud returned an invalid manifest payload." } }, 502);
9493
+ return c.json({ success: false, error: { code: "invalid_manifest", message: "Invalid manifest payload." } }, inlineManifest ? 400 : 502);
9293
9494
  }
9294
9495
  const conflict = this.findConflict(ctx, manifestId);
9295
9496
  if (conflict === "user-code") {
@@ -9301,6 +9502,18 @@ var MarketplaceInstallLocalPlugin = class {
9301
9502
  }
9302
9503
  }, 409);
9303
9504
  }
9505
+ try {
9506
+ const manifestService = ctx.getService("manifest");
9507
+ manifestService.register(manifest);
9508
+ } catch (err) {
9509
+ if (inlineManifest) {
9510
+ return c.json({
9511
+ success: false,
9512
+ error: { code: "register_failed", message: `Failed to register imported manifest: ${err?.message ?? err}` }
9513
+ }, 422);
9514
+ }
9515
+ ctx.logger?.warn?.(`[MarketplaceInstallLocal] hot-register failed for ${manifestId} (will load on next restart): ${err?.message ?? err}`);
9516
+ }
9304
9517
  const entry = {
9305
9518
  packageId,
9306
9519
  versionId: resolvedVersionId,
@@ -9312,20 +9525,14 @@ var MarketplaceInstallLocalPlugin = class {
9312
9525
  withSampleData: false
9313
9526
  };
9314
9527
  try {
9315
- (0, import_node_fs3.mkdirSync)(this.storageDir, { recursive: true });
9316
- (0, import_node_fs3.writeFileSync)((0, import_node_path6.join)(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9528
+ (0, import_node_fs4.mkdirSync)(this.storageDir, { recursive: true });
9529
+ (0, import_node_fs4.writeFileSync)((0, import_node_path7.join)(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9317
9530
  } catch (err) {
9318
9531
  return c.json({
9319
9532
  success: false,
9320
9533
  error: { code: "storage_failed", message: `Failed to persist manifest: ${err?.message ?? err}` }
9321
9534
  }, 500);
9322
9535
  }
9323
- try {
9324
- const manifestService = ctx.getService("manifest");
9325
- manifestService.register(manifest);
9326
- } catch (err) {
9327
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] hot-register failed for ${manifestId} (will load on next restart): ${err?.message ?? err}`);
9328
- }
9329
9536
  try {
9330
9537
  const ql = ctx.getService("objectql");
9331
9538
  if (ql && typeof ql.syncSchemas === "function") {
@@ -9339,7 +9546,7 @@ var MarketplaceInstallLocalPlugin = class {
9339
9546
  if (seededSummary.seeded.mode === "inline" && (seededSummary.seeded.inserted ?? 0) + (seededSummary.seeded.updated ?? 0) > 0) {
9340
9547
  entry.withSampleData = true;
9341
9548
  try {
9342
- (0, import_node_fs3.writeFileSync)((0, import_node_path6.join)(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9549
+ (0, import_node_fs4.writeFileSync)((0, import_node_path7.join)(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9343
9550
  } catch {
9344
9551
  }
9345
9552
  }
@@ -9386,12 +9593,12 @@ var MarketplaceInstallLocalPlugin = class {
9386
9593
  if (!manifestId) {
9387
9594
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9388
9595
  }
9389
- const file = (0, import_node_path6.join)(this.storageDir, safeFilename(manifestId));
9390
- if (!(0, import_node_fs3.existsSync)(file)) {
9596
+ const file = (0, import_node_path7.join)(this.storageDir, safeFilename(manifestId));
9597
+ if (!(0, import_node_fs4.existsSync)(file)) {
9391
9598
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9392
9599
  }
9393
9600
  try {
9394
- (0, import_node_fs3.unlinkSync)(file);
9601
+ (0, import_node_fs4.unlinkSync)(file);
9395
9602
  } catch (err) {
9396
9603
  return c.json({ success: false, error: { code: "storage_failed", message: err?.message ?? String(err) } }, 500);
9397
9604
  }
@@ -9414,7 +9621,7 @@ var MarketplaceInstallLocalPlugin = class {
9414
9621
  * (refuse to avoid silently overwriting authored code)
9415
9622
  */
9416
9623
  this.findConflict = (ctx, manifestId) => {
9417
- if ((0, import_node_fs3.existsSync)((0, import_node_path6.join)(this.storageDir, safeFilename(manifestId)))) {
9624
+ if ((0, import_node_fs4.existsSync)((0, import_node_path7.join)(this.storageDir, safeFilename(manifestId)))) {
9418
9625
  return "marketplace";
9419
9626
  }
9420
9627
  try {
@@ -9456,13 +9663,13 @@ var MarketplaceInstallLocalPlugin = class {
9456
9663
  if (!manifestId) {
9457
9664
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9458
9665
  }
9459
- const file = (0, import_node_path6.join)(this.storageDir, safeFilename(manifestId));
9460
- if (!(0, import_node_fs3.existsSync)(file)) {
9666
+ const file = (0, import_node_path7.join)(this.storageDir, safeFilename(manifestId));
9667
+ if (!(0, import_node_fs4.existsSync)(file)) {
9461
9668
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9462
9669
  }
9463
9670
  let entry;
9464
9671
  try {
9465
- entry = JSON.parse((0, import_node_fs3.readFileSync)(file, "utf8"));
9672
+ entry = JSON.parse((0, import_node_fs4.readFileSync)(file, "utf8"));
9466
9673
  } catch (err) {
9467
9674
  return c.json({ success: false, error: { code: "storage_failed", message: `Failed to read manifest cache: ${err?.message ?? err}` } }, 500);
9468
9675
  }
@@ -9478,7 +9685,7 @@ var MarketplaceInstallLocalPlugin = class {
9478
9685
  }
9479
9686
  try {
9480
9687
  entry.withSampleData = true;
9481
- (0, import_node_fs3.writeFileSync)(file, JSON.stringify(entry, null, 2), "utf8");
9688
+ (0, import_node_fs4.writeFileSync)(file, JSON.stringify(entry, null, 2), "utf8");
9482
9689
  } catch {
9483
9690
  }
9484
9691
  return c.json({
@@ -9510,13 +9717,13 @@ var MarketplaceInstallLocalPlugin = class {
9510
9717
  if (!manifestId) {
9511
9718
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9512
9719
  }
9513
- const file = (0, import_node_path6.join)(this.storageDir, safeFilename(manifestId));
9514
- if (!(0, import_node_fs3.existsSync)(file)) {
9720
+ const file = (0, import_node_path7.join)(this.storageDir, safeFilename(manifestId));
9721
+ if (!(0, import_node_fs4.existsSync)(file)) {
9515
9722
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9516
9723
  }
9517
9724
  let entry;
9518
9725
  try {
9519
- entry = JSON.parse((0, import_node_fs3.readFileSync)(file, "utf8"));
9726
+ entry = JSON.parse((0, import_node_fs4.readFileSync)(file, "utf8"));
9520
9727
  } catch (err) {
9521
9728
  return c.json({ success: false, error: { code: "storage_failed", message: `Failed to read manifest cache: ${err?.message ?? err}` } }, 500);
9522
9729
  }
@@ -9565,7 +9772,7 @@ var MarketplaceInstallLocalPlugin = class {
9565
9772
  }
9566
9773
  try {
9567
9774
  entry.withSampleData = false;
9568
- (0, import_node_fs3.writeFileSync)(file, JSON.stringify(entry, null, 2), "utf8");
9775
+ (0, import_node_fs4.writeFileSync)(file, JSON.stringify(entry, null, 2), "utf8");
9569
9776
  } catch {
9570
9777
  }
9571
9778
  ctx.logger?.info?.(`[MarketplaceInstallLocal] purged ${manifestId}: deleted=${deleted} skipped=${skipped} errors=${errors}`);
@@ -9663,7 +9870,7 @@ var MarketplaceInstallLocalPlugin = class {
9663
9870
  }
9664
9871
  }
9665
9872
  if (opts.seedNow && datasets.length > 0) {
9666
- const multiTenant = String(process.env.OS_MULTI_TENANT ?? "false").toLowerCase() !== "false";
9873
+ const multiTenant = String((0, import_types5.readEnvWithDeprecation)("OS_MULTI_ORG_ENABLED", "OS_MULTI_TENANT") ?? "false").toLowerCase() !== "false";
9667
9874
  try {
9668
9875
  const ql = ctx.getService("objectql");
9669
9876
  let metadata;
@@ -9764,12 +9971,12 @@ var MarketplaceInstallLocalPlugin = class {
9764
9971
  return null;
9765
9972
  };
9766
9973
  this.readAll = () => {
9767
- if (!(0, import_node_fs3.existsSync)(this.storageDir)) return [];
9974
+ if (!(0, import_node_fs4.existsSync)(this.storageDir)) return [];
9768
9975
  const out = [];
9769
- for (const name of (0, import_node_fs3.readdirSync)(this.storageDir)) {
9976
+ for (const name of (0, import_node_fs4.readdirSync)(this.storageDir)) {
9770
9977
  if (!name.endsWith(".json")) continue;
9771
9978
  try {
9772
- const raw = (0, import_node_fs3.readFileSync)((0, import_node_path6.join)(this.storageDir, name), "utf8");
9979
+ const raw = (0, import_node_fs4.readFileSync)((0, import_node_path7.join)(this.storageDir, name), "utf8");
9773
9980
  out.push(JSON.parse(raw));
9774
9981
  } catch {
9775
9982
  }
@@ -9777,7 +9984,7 @@ var MarketplaceInstallLocalPlugin = class {
9777
9984
  return out;
9778
9985
  };
9779
9986
  this.cloudUrl = resolveCloudUrl(config.controlPlaneUrl);
9780
- this.storageDir = config.storageDir ? (0, import_node_path6.resolve)(config.storageDir) : (0, import_node_path6.resolve)(process.cwd(), DEFAULT_DIR);
9987
+ this.storageDir = config.storageDir ? (0, import_node_path7.resolve)(config.storageDir) : (0, import_node_path7.resolve)(process.cwd(), DEFAULT_DIR);
9781
9988
  }
9782
9989
  };
9783
9990
 
@@ -9809,6 +10016,7 @@ init_body_runner();
9809
10016
  // src/index.ts
9810
10017
  var import_rest = require("@objectstack/rest");
9811
10018
  __reExport(index_exports, require("@objectstack/core"), module.exports);
10019
+ var import_types6 = require("@objectstack/types");
9812
10020
  // Annotate the CommonJS export names for ESM import in node:
9813
10021
  0 && (module.exports = {
9814
10022
  AppPlugin,
@@ -9847,6 +10055,7 @@ __reExport(index_exports, require("@objectstack/core"), module.exports);
9847
10055
  SandboxError,
9848
10056
  SeedLoaderService,
9849
10057
  UnimplementedScriptRunner,
10058
+ _resetEnvDeprecationWarnings,
9850
10059
  actionBodyRunnerFactory,
9851
10060
  backfillPlatformSsoClients,
9852
10061
  buildPlatformSsoRedirectUri,
@@ -9871,6 +10080,7 @@ __reExport(index_exports, require("@objectstack/core"), module.exports);
9871
10080
  mergeRuntimeModule,
9872
10081
  parseTraceparent,
9873
10082
  readArtifactSource,
10083
+ readEnvWithDeprecation,
9874
10084
  resolveCloudUrl,
9875
10085
  resolveDefaultArtifactPath,
9876
10086
  resolveErrorReporter,